﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FlexiCommerce.Persistence.NH;
using NUnit.Framework;
using FlexiCommerce.Components;

namespace FlexiCommerce.Tests.Persistence.NH
{
    [TestFixture]
    public class ProductRepositoryTests : DatabasePreparingBase
    {
        NHRepository<int, Product> repository;
        ISessionProvider sessionProvider;

        [SetUp]
        public override void SetUp()
        {
            base.SetUp();
            CreateDatabaseSchema();

            sessionProvider = CreateSessionProvider();
            repository = new NHRepository<int, Product>(sessionProvider);
        }

        [Test]
        public void CanSave()
        {
            int itemID = SaveAnItem("savedItem", null);
            Assert.AreNotEqual(0, itemID);

            using (repository)
            {
                Product item = repository.Get<Product>(itemID);
                Assert.AreEqual(item.ID, itemID);
                repository.Delete(item);
                repository.Flush();
            }
        }

        [Test]
        public void CanUpdate()
        {
            int itemID = SaveAnItem("savedItem", null);

            using (repository)
            {
                Product item = repository.Get<Product>(itemID);
                item.Name = "updated item";
                repository.SaveOrUpdate(item);
                repository.Flush();
            }

            using (repository)
            {
                Product item = repository.Get<Product>(itemID);
                Assert.AreEqual("updated item", item.Name);
                repository.Delete(item);
                repository.Flush();
            }
        }

        [Test]
        public void CanFindAll()
        {
            int item1ID = SaveAnItem("first", null);
            int item2ID = SaveAnItem("second", null);
            int item3ID = SaveAnItem("third", null);

            using (repository)
            {
                ICollection<Product> items = repository.FindAll();
                Assert.AreEqual(3, items.Count);
                repository.Flush();
            }
        }

        [Test]
        public void CanDelete()
        {
            int itemID = SaveAnItem("k", null);

            using (repository)
            {
                Product item = repository.Get<Product>(itemID);
                Assert.IsNotNull(item, "There should be a saved item.");
                repository.Delete(item);
                repository.Flush();
            }

            using (repository)
            {
                Product item = repository.Get<Product>(itemID);
                Assert.IsNull(item, "Item is supposed to be deleted");
                repository.Flush();
            }
        }

        [Test]
        public void CanFindGreaterThanID()
        {
            int item1ID = SaveAnItem("first", null);
            int item2ID = SaveAnItem("second", null);
            int item3ID = SaveAnItem("third", null);

            using (repository)
            {
                ICollection<Product> items = repository.FindAll(NHibernate.Criterion.Expression.Gt("ID", 1));
                Assert.AreEqual(2, items.Count);
                repository.Flush();
            }
        }

        [Test]
        public void CanSaveDetail()
        {
            int item1ID = SaveAnItem("category 1", null);
            int item2ID = SaveAnItem("category 2", null);
            Culture lane = Culture.English;
            Culture lans = Culture.Spanish;

            Product prod = engine.Persister.Get<Product>(item1ID);
            Assert.AreEqual(0, prod.Details.Count);
            prod.AddDetail(new ProductDetails("name", lane));
            prod.AddDetail(new ProductDetails("sname", lans));
            engine.Persister.Save(prod);
            prod = engine.Persister.Get<Product>(item1ID);
            Assert.AreEqual(2, prod.Details.Count);
            int details1ID = prod.Details[0].ID;
            int details2ID = prod.Details[1].ID;
            ProductDetails detaile = Find.ProductDetails.Where(d => d.Product == prod).Where(d => d.Culture == lane).SingleOrDefault();
            ProductDetails details = Find.ProductDetails.Where(d => d.Product == prod).Where(d => d.Culture == lans).SingleOrDefault();
            Assert.AreEqual(detaile.Culture, lane);
            Assert.AreEqual(details.Culture, lans);
            Assert.AreEqual(details.Product, prod);
            Assert.AreEqual(detaile.Product, prod);

            repository.Flush();

        }


        [Test]
        public void CanHaveCategories()
        {
            Product product1 = engine.Persister.Get<Product>(SaveAnItem("first", null));
            Product product2 = engine.Persister.Get<Product>(SaveAnItem("second", null));

            Category cat1 = new Category();
            Category cat2 = new Category();

            cat1.Name = "Product 1";
            cat2.Name = "Product 2";

            engine.Persister.Save(cat1);
            engine.Persister.Save(cat2);

            Assert.AreEqual(0, product1.Categories.Count);
            Assert.AreEqual(0, product2.Categories.Count);

            product1.Categories.Add(cat1);

            product2.Categories.Add(cat1);
            product2.Categories.Add(cat2);

            engine.Persister.Save(product1);
            engine.Persister.Save(product2);

            product1 = engine.Persister.Get<Product>(product1.ID);
            product2 = engine.Persister.Get<Product>(product2.ID);

            Assert.AreEqual(1, product1.Categories.Count);
            EnumerableAssert.Contains(product1.Categories, product1);

            Assert.AreEqual(2, product2.Categories.Count);
            EnumerableAssert.Contains(product2.Categories, cat1);
            EnumerableAssert.Contains(product2.Categories, cat2);

        }

        private int SaveAnItem(string name, HierarchicalPersistenceItem parent)
        {
            try
            {
                
                    Product item = CreateOneItem<Product>(0, name, parent);
                    engine.Persister.Save(item);
                    engine.Persister.Flush();
                    return item.ID;
               
            }
            catch (Exception)
            {
                return 0;
            }


        }


    }
}
